/*
 * Copyrignt (c) xuzeshui.com. All Rights Reserved.
 * Author: Zeshui Xu<i@xuzeshui.com>
 * Created Time: 2015-11-29 16:35:23
 * Last Modified: 2016-03-25 11:37:41
 * File Name: ip/ip.go
 * Description:
 */
package ip

import (
	"bufio"
	"fmt"
	"io"
	"os"
	"strconv"
	"strings"
)

var (
	ipdata []*IPItem
)

/*
	IP纪录信息
*/
type IPItem struct {
	StartIP    uint32 `json:"-"`
	EndIP      uint32 `json:"-"`
	CountryId  string `json:"country_id"`
	Country    string `json:"country"`
	ISPId      string `json:"isp_id"`
	ISP        string `json:"isp"`
	ProvinceId string `json:"province_id"`
	Province   string `json:"province"`
	CityId     string `json:"city_id"`
	City       string `json:"city"`
	CountyId   string `json:"county_id"`
	County     string `json:"county"`
	AreaId     string `json:"area_id"`
	Area       string `json:"area"`
	RegionCode string `json:"region_code"`
}

/*
	IP定位
*/
func IPLocation(ip string) *IPItem {
	val, ok := ip2long(ip)
	if !ok {
		return nil
	}
	i, j := 0, len(ipdata)-1
	var itemFound *IPItem
	for i <= j {
		m := (i + j) / 2
		item := ipdata[m]
		if item.StartIP <= val && item.EndIP >= val {
			itemFound = item
			break
		} else if item.StartIP > val {
			j = m - 1
		} else {
			i = m + 1
		}
	}
	return itemFound
}

func ip2long(ip string) (uint32, bool) {
	r := strings.Split(ip, ".")
	if len(r) != 4 {
		return 0, false
	}
	ip1, _ := strconv.Atoi(r[0])
	ip2, _ := strconv.Atoi(r[1])
	ip3, _ := strconv.Atoi(r[2])
	ip4, _ := strconv.Atoi(r[3])
	if ip1 > 255 || ip2 > 255 || ip3 > 255 || ip4 > 255 {
		return 0, false
	}
	var ipval uint32 = 0
	ipval += uint32(ip1 * 0x1000000)
	ipval += uint32(ip2 * 0x10000)
	ipval += uint32(ip3 * 0x100)
	ipval += uint32(ip4)
	return ipval, true
}

func loadIPData() {
	dbfile := "../db/taobaoip.txt"
	f, err := os.Open(dbfile)
	if err != nil {
		fmt.Printf("open dbfile: %s error: %s", dbfile, err.Error())
		return
	}
	defer f.Close()
	rd := bufio.NewReader(f)
	dat := make([]*IPItem, 0, 0)
	for {
		line, err := rd.ReadString('\n')
		if err != nil || io.EOF == err {
			break
		}
		r := strings.Split(strings.TrimSpace(line), "|")
		if len(r) != 14 {
			continue
		}
		//Foramt like
		//1.2.2.0|1.2.2.255|CN|中国|1000120|北龙中网|110000|北京市|110100|北京市|110108|海淀区|100000|华北
		item := &IPItem{}
		item.StartIP, _ = ip2long(r[0])
		item.EndIP, _ = ip2long(r[1])
		item.CountryId = r[2]
		item.Country = r[3]
		item.ISPId = r[4]
		item.ISP = r[5]
		item.ProvinceId = r[6]
		item.Province = r[7]
		item.CityId = r[8]
		item.City = r[9]
		item.CountyId = r[10]
		item.County = r[11]
		item.AreaId = r[12]
		item.Area = r[13]
		fixItemValue(item)
		dat = append(dat, item)
	}
	fmt.Println(len(dat))
	ipdata = dat
}

func fixItemValue(item *IPItem) {
	if item.CountryId != "CN" {
		return
	}
	regionCode := ""
	if "-1" != item.ProvinceId && len(item.ProvinceId) >= 2 {
		item.ProvinceId = item.ProvinceId[0:2]
		regionCode = item.ProvinceId
	} else {
		item.ProvinceId = ""
	}
	if "-1" != item.CityId && len(item.CityId) >= 4 {
		item.CityId = item.CityId[0:4]
		regionCode = item.CityId
	}
	if "-1" != item.CountyId && len(item.CountyId) >= 6 {
		item.CountyId = item.CountyId[0:6]
		regionCode = item.CountyId
	}
	item.RegionCode = regionCode
}

func init() {
	go loadIPData()
}
